#lang scribble/doc
@(require scribble/manual scribble/eval scribble/racket
          "guide-utils.rkt" "modfile.rkt"
          (for-syntax racket/base)
          (for-label setup/dirs
                     syntax/strip-context
                     syntax-color/default-lexer))

@(define-syntax ! (make-element-id-transformer (lambda (v) #'@tt{|})))
@(define-syntax !- (make-element-id-transformer (lambda (v) #'@tt{|-})))


@;{@title[#:tag "hash-languages" #:style 'toc]{Defining new @hash-lang[] Languages}}
@title[#:tag "hash-languages" #:style 'toc]{定义新的@hash-lang[]语言}

@;{When loading a module as a source program that starts}
将模块作为启动的源程序加载时

@racketmod[
@#,racket[_language]
]

@;{the @racket[_language] determines the way that the rest of the module
is parsed at the @tech{reader} level. The @tech{reader}-level parse
must produce a @racket[module] form as a @tech{syntax object}. As
always, the second sub-form after @racket[module] specifies the
@tech{module language} that controls the meaning of the module's body
forms. Thus, a @racket[_language] specified after @hash-lang[]
controls both the @tech{reader}-level and @tech{expander}-level
parsing of a module.}
@racket[_language]决定了在@tech{读取器}级别解析模块其余部分的方式。@tech{读取器}级别解析必须生成一个@racket[module]表作为@tech{语法对象}。与以往一样，@racket[module]后面的第二个子表指定了控制模块主体表含义的@tech{模块语言（module language）}。因此，在@racket[_language]之后指定的@hash-lang[]控制模块的@tech{读取器}级别和@tech{扩展器}级别解析。

@local-table-of-contents[]

@; ----------------------------------------
@;{@section[#:tag "hash-lang syntax"]{Designating a @hash-lang[] Language}}
@section[#:tag "hash-lang syntax"]{指定@hash-lang[]语言}

@;{The syntax of a @racket[_language] intentionally overlaps with the
syntax of a module path as used in @racket[require] or as a
@tech{module language}, so that names like @racketmodname[racket],
@racketmodname[racket/base], @racketmodname[slideshow], or
@racketmodname[scribble/manual] can be used both as @hash-lang[]
languages and as module paths.}
@racket[_language]的语法有意与@racket[require]或@tech{模块语言（module language）}中使用的模块路径的语法重叠，因此像@racketmodname[racket]、@racketmodname[racket/base]、@racketmodname[slideshow]或@racketmodname[scribble/manual]这样的名称既可以用作@hash-lang[]语言，也可用作模块路径。

@;{At the same time, the syntax of @racket[_language] is far more
restricted than a module path, because only @litchar{a}-@litchar{z},
@litchar{A}-@litchar{Z}, @litchar{0}-@litchar{9},
@litchar{/} (not at the start or end),
@litchar{_}, @litchar{-}, and @litchar{+} are allowed in a
@racket[_language] name. These restrictions keep the syntax of
@hash-lang[] as simple as possible. Keeping the syntax of @hash-lang[]
simple, in turn, is important because the syntax is inherently
inflexible and non-extensible; the @hash-lang[] protocol allows a
@racket[_language] to refine and define syntax in a practically
unconstrained way, but the @hash-lang[] protocol itself must remain
fixed so that various different tools can ``boot'' into the extended
world.}
同时，@racket[_language]的语法比模块路径更受限制，因为只有@litchar{a}-@litchar{z}、@litchar{A}-@litchar{Z}、@litchar{0}-@litchar{9}、@litchar{/}（不在开头或结尾）、@racket[_language]名称中允许使用@litchar{_}、@litchar{-}和@litchar{+}。这些限制使@hash-lang[]语法尽可能简单。反过来，保持@hash-lang[]语法简单也很重要，因为语法本身就不灵活且不可扩展；@hash-lang[]协议允许@racket[_language]以一种几乎不受约束的方式细化和定义语法，但@hash-lang[]协议本身必须保持固定，以便各种不同的工具能够“引导”到扩展世界。

@;{Fortunately, the @hash-lang[] protocol provides a natural way to refer
to languages in ways other than the rigid @racket[_language] syntax:
by defining a @racket[_language] that implements its own nested
protocol. We have already seen one example (in @secref["s-exp"]): the
@racketmodname[s-exp] @racket[_language] allows a programmer to
specify a @tech{module language} using the general @tech{module path}
syntax. Meanwhile, @racketmodname[s-exp] takes care of the
@tech{reader}-level responsibilities of a @hash-lang[] language.}
幸运的是，@hash-lang[]协议提供了一种自然的方式来引用语言，而不是严格的@racket[_language]语法：通过定义一个实现自己的嵌套协议的@racket[_language]。我们已经看到了一个例子（在《@secref["s-exp"]》里）：@racketmodname[s-exp]的@racket[_language]允许程序员使用通用的@tech{模块路径}语法指定@tech{模块语言}。同时，@racketmodname[s-exp]负责@hash-lang[]语言的@tech{读取器}级别职责。

@;{Unlike @racketmodname[racket], @racketmodname[s-exp] cannot be used as a
module path with @racket[require]. Although the syntax of
@racket[_language] for @hash-lang[] overlaps with the syntax of module
paths, a @racket[_language] is not used directly as a module
path. Instead, a @racket[_language] obtains a module path by trying two 
locations:  first, it looks for a @racketidfont{reader} submodule of the 
main module for  @racket[_language]. If this is not a valid module path, 
then @racket[_language]  is suffixed with @racketidfont{/lang/reader}. 
(If neither is a valid module path, an error is raised.) The resulting 
module supplies @racketidfont{read} and @racketidfont{read-syntax}
functions using a protocol that is similar to the one for
@racketmetafont{#reader}.}
不同于@racketmodname[racket]，@racketmodname[s-exp]不能作用带有@racket[require]的模块路径。尽管@hash-lang[]的@racket[_language]语法与模块路径语法重叠，但@racket[_language]不能直接用作模块路径。相反，@racket[_language]通过尝试两个位置获得模块路径：首先，它为@racket[_language]查找主模块的@racketidfont{读取器}子模块。如果这不是有效的模块路径，那么@racket[_language]将用@racketidfont{/lang/reader}作为后缀。（如果两者都不是有效的模块路径，则会引发错误。）生成的模块使用与@racketmetafont{#reader}类似的协议提供@racketidfont{read}和@racketidfont{read-syntax}函数。

@;{@guideother{@secref["hash-reader"] introduces @racketmetafont{#reader}.}}
@guideother{《@secref["hash-reader"]》介绍了@racketmetafont{#reader}.}

@;{A consequence of the way that a @hash-lang[] @racket[_language] is
turned into a module path is that the language must be installed in a
@tech{collection}, similar to the way that @filepath{racket} or
@filepath{slideshow} are collections that are distributed with Racket.
Again, however, there's an escape from this restriction: the
@racketmodname[reader] language lets you specify a @tech{reader}-level
implementation of a language using a general @tech{module path}.}
将@hash-lang[]的@racket[_language]转换为模块路径的一个结果是，该语言必须安装在@tech{集合（collection）}中，类似于@filepath{racket}或@filepath{slideshow}是随Racket分发的集合。然而，还有一个例外：@racketmodname[reader]语言允许你使用通用@tech{模块路径}指定语言的@tech{读取器}级实现。

@; ----------------------------------------
@;{@section[#:tag "hash-lang reader"]{Using @racket[@#,hash-lang[] @#,racketmodname[reader]]}}
@section[#:tag "hash-lang reader"]{使用@racket[@#,hash-lang[] @#,racketmodname[reader]]}

@;{The @racketmodname[reader] language for @hash-lang[] is similar to
@racketmodname[s-exp], in that it acts as a kind of meta-language.
Whereas @racketmodname[s-exp] lets a programmer specify a @tech{module
language} at the @tech{expander} layer of parsing,
@racketmodname[reader] lets a programmer specify a language at the
@tech{reader} level.}
@hash-lang[]的@racketmodname[reader]语言类似于@racketmodname[s-exp]，因为它是一种元语言。@racketmodname[s-exp]允许程序员在@tech{扩展器}解析层指定@tech{模块语言}，而@racketmodname[reader]允许程序员指定@tech{读取器}层的语言。

@;{A @racket[@#,hash-lang[] @#,racketmodname[reader]] must be followed by
a module path, and the specified module must provide two functions:
@racketidfont{read} and @racketidfont{read-syntax}. The protocol is
the same as for a @racketmetafont{#reader} implementation, but for
@hash-lang[], the @racketidfont{read} and @racketidfont{read-syntax}
functions must produce a @racket[module] form that is based on the
rest of the input file for the module.}
@racket[@#,hash-lang[] @#,racketmodname[reader]]后面必须有一个模块路径，并且指定的模块必须提供两个函数：@racketidfont{read}和@racketidfont{read-syntax}。该协议与@racketmetafont{#reader}实现的协议相同，但对于@hash-lang[]，@racketidfont{read}和@racketidfont{read-syntax}函数必须生成一个基于模块输入文件其余部分的@racket[module]表。

@;{The following @filepath{literal.rkt} module implements a language that
treats its entire body as literal text and exports the text as a
@racketidfont{data} string:}
下面的@filepath{literal.rkt}模块实现了一种语言，该语言将其整个正文视为文本，并将文本导出为@racketidfont{数据}字符串：

@racketmodfile["literal.rkt"]

@;{The @filepath{literal.rkt} language uses @racket[strip-context] on the
generated @racket[module] expression, because a
@racketidfont{read-syntax} function should return a syntax object with
no lexical context. Also, the @filepath{literal.rkt} language creates
a module named @racketidfont{anything}, which is an arbitrary choice;
the language is intended to be used in a file, and the longhand module
name is ignored when it appears in a @racket[require]d file.}
@filepath{literal.rkt}语言在生成的@racket[module]表达式上使用@racket[strip-context]，因为@racketidfont{read-syntax}函数应该返回一个没有词法上下文的语法对象。此外，@filepath{literal.rkt}语言创建了一个名为@racketidfont{anything}的模块，这是一个随意的选择；该语言旨在在文件中使用，当普通书写的模块名称出现在@racket[require]文件中时，它将被忽略。

@;{The @filepath{literal.rkt} language can be used in a module
@filepath{tuvalu.rkt}:}
@filepath{literal.rkt}语言可以在模块中使用@filepath{tuvalu.rkt}：

@racketmodfile["tuvalu.rkt"]

@;{Importing @filepath{tuvalu.rkt} binds @racketidfont{data} to a
string version of the module content:}
导入@filepath{tuvalu.rkt}将@racketidfont{data}绑定到模块内容的字符串版本：

@interaction[
(require "tuvalu.rkt")
data
]

@; ----------------------------------------
@;{@section[#:tag "syntax/module-reader"]{Using @racket[@#,hash-lang[] @#,racketmodname[s-exp] @#,racketmodname[syntax/module-reader]]}}
@section[#:tag "syntax/module-reader"]{使用@racket[@#,hash-lang[] @#,racketmodname[s-exp] @#,racketmodname[syntax/module-reader]]}

@;{Parsing a module body is usually not as trivial as in
@filepath{literal.rkt}. A more typical module parser must iterate to
parse multiple forms for a module body. A language is also more likely
to extend Racket syntax---perhaps through a @tech{readtable}---instead
of replacing Racket syntax completely.}
解析模块主体通常不像@filepath{literal.rkt}中那样简单。更典型的模块解析器必须迭代以解析模块体的多个表单。一种语言也更有可能扩展Racket语法——也许通过@tech{readtable}——而不是完全替换Racket句法。
@;{The @racketmodname[syntax/module-reader] @tech{module language}
abstracts over common parts of a language implementation to simplify
the creation of new languages. In its most basic form, a language
implemented with @racketmodname[syntax/module-reader] simply specifies
the @tech{module language} to be used for the language, in which case
the @tech{reader} layer of the language is the same as Racket. For
example, with}
@racketmodname[syntax/module-reader]@tech{模块语言}对语言实现的公共部分进行抽象，以简化新语言的创建。在最基本的形式中，用@racketmodname[syntax/module-reader]实现的语言只指定了该语言使用的@tech{模块语言}，在这种情况下，该语言的@tech{读取器}层与Racket相同。例如，使用

@racketmod[
#:file "raquet-mlang.rkt"
racket
(provide (except-out (all-from-out racket) lambda)
         (rename-out [lambda function]))
]

@;{and}
以及

@racketmod[
#:file "raquet.rkt"
s-exp syntax/module-reader
"raquet-mlang.rkt"
]

@;{then}
那么

@racketmod[
reader "raquet.rkt"
(define identity (function (x) x))
(provide identity)
]

@;{implements and exports the @racket[identity] function, since
@filepath{raquet-mlang.rkt} exports @racket[lambda] as
@racket[function].}
由于@filepath{raquet-mlang.rkt}将@racket[lambda]导出为@racket[function]，因此实现并导出@racket[identity]函数。

@;{The @racketmodname[syntax/module-reader] language accepts many optional
specifications to adjust other features of the language. For example,
an alternate @racketidfont{read} and @racketidfont{read-syntax} for
parsing the language can be specified with @racket[#:read] and
@racket[#:read-syntax], respectively. The following
@filepath{dollar-racket.rkt} language uses @filepath{dollar.rkt} (see
@secref["readtable"]) to build a language that is like
@racketmodname[racket] but with a @litchar{$} escape to simple infix
arithmetic:}
@racketmodname[syntax/module-reader]语言接受许多可选的规范来调整语言的其它特性。例如，替换的@racketidfont{read}和@racketidfont{read-syntax}解析语言可以使用@racket[#:read]和@racket[#:read-syntax]。以下内容@filepath{dollar-racket.rkt}语言使用@filepath{dollar.rkt}（见《@secref["readtable"]》）来构建类似@racketmodname[racket]，但带有@litchar{$}转义为简单中缀算术：

@racketmodfile["dollar-racket.rkt"]

@;{The @racket[require] form appears at the end of the module,
because all of the keyword-tagged optional specifications for
@racketmodname[syntax/module-reader] must appear before any helper
imports or definitions.}
@racket[require]表出现在模块的末尾，因为@racketmodname[syntax/module-reader]的所有关键字标记的可选规范必须出现在任何助手导入或定义之前。

@;{The following module uses @filepath{dollar-racket.rkt} to implement a
@racket[cost] function using a @litchar{$} escape:}
下面的模块使用@filepath{dollar-racket.rkt}来使用@litchar{$}转义实现@racket[cost]函数：

@racketmodfile["store.rkt"]

@; ----------------------------------------
@;{@section[#:tag "language-collection"]{Installing a Language}}
@section[#:tag "language-collection"]{安装语言}

@;{So far, we have used the @racketmodname[reader] meta-language to
access languages like @filepath{literal.rkt} and
@filepath{dollar-racket.rkt}. If you want to use something like
@racket[@#,hash-lang[] literal] directly, then you must move
@filepath{literal.rkt} into a Racket @tech{collection} named
@filepath{literal} (see also @secref["link-collection"]).
Specifically, move @filepath{literal.rkt} to a @racketidfont{reader} 
submodule of @filepath{literal/main.rkt} for any directory name
@filepath{literal}, like so:}
到目前为止，我们已经使用@racketmodname[reader]元语言来访问@filepath{literal.rkt}和@filepath{dollar-racket.rkt}。如果你想直接使用@racket[@#,hash-lang[] literal]之类的，那你必须把@filepath{literal.rkt}移到名为@filepath{literal}的Racket@tech{集合}中（另请参见《@secref["link-collection"]》）。具体而言，将@filepath{literal.rkt}移到任何目录名@filepath{literal/main.rkt}的@racketidfont{reader}子模块中，如下所示：

@racketmodfile["literal-main.rkt" "literal/main.rkt"]

@;{Then, install the @filepath{literal}
directory as a package:}
然后，将@filepath{literal}目录作为包安装：

@commandline{cd /path/to/literal ; raco pkg install}

@;{After moving the file and installing the package, you can use
@racket[literal] directly after @hash-lang[]:}
移动文件并安装包后，可以在@hash-lang[]后面直接使用@racket[literal]。

@racketmod[
@#,racket[literal]
Technology!
System!
Perfect!
]

@;{@margin-note{See @other-manual['(lib "scribblings/raco/raco.scrbl")]
for more information on using @exec{raco}.}}
@margin-note{有关使用@exec{宏}的详细信息参见《@other-manual['(lib "scribblings/raco/raco.scrbl")]》。}

@;{You can also make your language available for others to install by
using the Racket package manager (see @other-doc['(lib
"pkg/scribblings/pkg.scrbl")]). After you create a @filepath{literal}
package and register it with the Racket package catalog (see
@secref["concept:catalog" #:doc '(lib "pkg/scribblings/pkg.scrbl")]),
others can install it using @exec{raco pkg}:}
你还可以使用Racket包管理器（参见《@other-doc['(lib
"pkg/scribblings/pkg.scrbl")]》）将您的语言提供给其他人安装。创造@filepath{literal}包并将其注册到Racket包目录（请参见《@secref["concept:catalog" #:doc '(lib "pkg/scribblings/pkg.scrbl")]》）后，其他人就可以使用@exec{raco pkg}安装它：

@commandline{raco pkg install literal}

@;{Once installed, others can invoke the language the same way: by using
@racket[@#,hash-lang[] literal] at the top of a source file.}
安装后，其他人可以用同样的方式调用该语言：在源文件的顶部使用@racket[@#,hash-lang[] literal]。

@;{If you use a public source repository (e.g., GitHub), you can link
your package to the source. As you improve the package, others can
update their version using @exec{raco pkg}:}
如果你使用公共源代码库（例如GitHub），你可以将你的包链接到源代码。当你改进这个包，其他人可以使用@exec{raco pkg}更新其的版本：

@commandline{raco pkg update literal}

@;{@margin-note{See @other-doc['(lib "pkg/scribblings/pkg.scrbl")] for more
information about the Racket package manager.}}
@margin-note{了解有关Racket包管理器的更多信息，请参见@other-doc['(lib "pkg/scribblings/pkg.scrbl")]。}

@; ----------------------------------------
@;{section[#:tag "language-get-info"]{Source-Handling Configuration}}
@section[#:tag "language-get-info"]{源处理配置}

@;{The Racket distribution includes a Scribble language for writing prose
documents, where Scribble extends the normal Racket to better support
text. Here is an example Scribble document:}
Racket发行版包括用于编写平常文档的Scribble语言，其中Scribble扩展了普通Racket以更好地支持文本。下面是一个示例Scribble文档：

@verbatim[#:indent 2]|{
#lang scribble/base

@(define (get-name) "Self-Describing Document")

@title[(get-name)]

The title of this document is ``@(get-name).''
}|

@;{If you put that program in DrRacket's @tech{definitions area} and
click @onscreen{Run}, then nothing much appears to happen. The
@racketmodname[scribble/base] language just binds and exports
@racketidfont{doc} as a description of a document, similar to the way
that @filepath{literal.rkt} exports a string as @racketidfont{data}.}
如果你将该程序放在DrRacket的@tech{定义区域}中并单击@onscreen{Run}，那么是乎不会发生什么。@racketmodname[scribble/base]语言只绑定并导出@racketidfont{doc}作为文档的描述，类似于@filepath{literal.rkt}将字符串导出为@racketidfont{data}的方式。

@;{Simply opening a module with the language
@racketmodname[scribble/base] in DrRacket, however, causes a
@onscreen{Scribble HTML} button to appear. Furthermore, DrRacket knows
how to colorize Scribble syntax by coloring green those parts of the
document that correspond to literal text. The language name
@racketmodname[scribble/base] is not hard-wired into
DrRacket. Instead, the implementation of the
@racketmodname[scribble/base] language provides button and
syntax-coloring information in response to a query from DrRacket.}
然而，只需在DrRacket中打开一个带有@racketmodname[scribble/base]语言的模块，就会出现一个@onscreen{Scribble HTML}按钮。此外，DrRacket知道如何通过将文档中与文字相对应的部分着色为绿色来为Scribble语法着色。语言名称@racketmodname[scribble/base]不是硬连接的DrRacket。相反，@racketmodname[scribble/base]语言的实现提供了按钮和语法着色信息，以响应DrRacket的查询。

@;{If you have installed the @racket[literal] language as described in
@secref["language-collection"], then you can adjust
@filepath{literal/main.rkt} so that DrRacket treats the content
of a module in the @racket[literal] language as plain text instead of
(erroneously) as Racket syntax:}
如果你已经安装了@secref["language-collection"]中描述的@racket[literal]语言，那你可以调整@filepath{literal/main.rkt}，以便DrRacket将@racket[literal]语言中的模块内容视为纯文本，而不是（错误地）视为Racket语法：

@racketmodfile["literal-main-get-info.rkt" "literal/main.rkt"]

@;{This revised @racket[literal] implementation provides a
@racketidfont{get-info} function. The @racketidfont{get-info} function
is called by @racket[read-language] (which DrRacket calls) with the 
source input stream and location information,
in case query results should depend on the content of the module after
the language name (which is not the case for @racket[literal]). The
result of @racketidfont{get-info} is a function of two arguments. The
first argument is always a symbol, indicating the kind of information
that a tool requests from the language; the second argument is the
default result to be returned if the language does not recognize the
query or has no information for it.}
这个修改后的@racket[literal]实现提供了一个@racketidfont{get-info}函数。@racketidfont{get-info}函数由@racket[read-language]（DrRacket调用）源输入流和位置信息，以防查询结果应取决于语言名称后面的模块内容（@racket[literal]不是这样）。@racketidfont{get-info}的结果是两个参数的函数。第一个参数总是一个符号，表示工具从语言中请求的信息类型；如果语言无法识别查询或没有查询信息，则第二个参数是返回的默认结果。

@;{After DrRacket obtains the result of @racketidfont{get-info} for a
language, it calls the function with a @racket['color-lexer] query;
the result should be a function that implements syntax-coloring
parsing on an input stream. For @racket[literal], the
@racketmodname[syntax-color/default-lexer] module provides a
@racket[default-lexer] syntax-coloring parser that is suitable for
plain text, so @racket[literal] loads and returns that parser in
response to a @racket['color-lexer] query.}
DrRacket获得一种语言的@racketidfont{get-info}结果后，它使用@racket['color-lexer]查询调用该函数；结果应该是一个在输入流上实现语法着色解析的函数。对于@racket[literal]，@racketmodname[syntax-color/default-lexer]模块提供了一个适用于纯文本的@racket[default-lexer]语法着色解析器，因此@racket[literal]加载并返回该解析器以响应@racket['color-lexer]查询。

@;{The set of symbols that a programming tool uses for queries
is entirely between the tool and the languages that choose to
cooperate with it. For example, in addition to @racket['color-lexer],
DrRacket uses a @racket['drracket:toolbar-buttons] query to determine
which buttons should be available in the toolbar to operate on modules
using the language.}
编程工具用于查询的符号集完全在工具和选择与之合作的语言之间。例如，除了@racket['color-lexer]之外，DrRacket还使用@racket['drracket:toolbar-buttons]查询来确定工具栏中哪些按钮可以使用该语言在模块上操作。

@;{The @racketmodname[syntax/module-reader] language lets you specify
@racketidfont{get-info} handling through a @racket[#:info] optional
specification. The protocol for an @racket[#:info] function is
slightly different from the raw @racketidfont{get-info} protocol; the
revised protocol allows @racketmodname[syntax/module-reader] the
possibility of handling future language-information queries
automatically.}
@racketmodname[syntax/module-reader]语言允许你通过@racket[#:info]可选规范指定@racketidfont{get-info}处理。@racket[#:info]函数的协议与原始@racketidfont{get-info}协议略有不同；修订后的协议允许@racketmodname[syntax/module-reader]自动处理未来的语言信息查询。

@; ----------------------------------------
@;{@section[#:tag "module-runtime-config"]{Module-Handling Configuration}}
@section[#:tag "module-runtime-config"]{模块处理配置}

@;{Suppose that the file @filepath{death-list-5.rkt} contains}
假设文件@filepath{death-list-5.rkt}包含

@racketmodfile["death-list-5.rkt"]

@;{If you @racket[require] @filepath{death-list-5.rkt} directly, then it
prints the list in the usual Racket result format:}
如果你直接@racket[require] @filepath{death-list-5.rkt}，那么它会以通常的Racket结果格式打印列表：

@interaction[
(require "death-list-5.rkt")
]

@;{However, if @filepath{death-list-5.rkt} is required by a
@filepath{kiddo.rkt} that is implemented with @racketmodname[scheme]
instead of @racketmodname[racket]:}
但是，如果@filepath{death-list-5.rkt}是由@filepath{kiddo.rkt}所要求的，该@filepath{kiddo.rkt}是用@racketmodname[scheme]而不是用@racketmodname[racket]实现的：

@racketmodfile["kiddo.rkt"]

@;{then, if you run @filepath{kiddo.rkt} file in DrRacket or if you run it
directly with @exec{racket}, @filepath{kiddo.rkt} causes
@filepath{death-list-5.rkt} to print its list in traditional Scheme
format, without the leading quote:}
然后，如果你在DrRacket中运行@filepath{kiddo.rkt}文件，或者直接使用@exec{racket}运行该文件，@filepath{kiddo.rkt}导致@filepath{death-list-5.rkt}以传统的Scheme格式打印其列表，而不是使用前导引号：

@racketblock[
@#,racketoutput{("O-Ren Ishii" "Vernita Green" "Budd" "Elle Driver" "Bill")}
]

@;{The @filepath{kiddo.rkt} example illustrates how the format for
printing a result value can depend on the main module of a program
instead of the language that is used to implement it.}
@filepath{kiddo.rkt}示例说明了打印结果值的格式如何依赖于程序的主模块而不是用于实现它的语言。

@;{More broadly, certain features of a language are only invoked when
a module written in that language is run directly with @exec{racket}
(as opposed to being imported into another module). One example is
result-printing style (as shown above). Another example is REPL
behavior. These features are part of what's called the
@deftech{run-time configuration} of a language.}
更广泛地说，只有当用一种语言编写的模块直接用@exec{racket}运行（而不是导入导另一个模块中），才会调用该语言的某些特性。一个例子是结果打印样式（如上所示）。另一个例子是REPL行为。这些特性是语言的@deftech{运行时配置（run-time configuration）}的一部分。

@;{Unlike the syntax-coloring property of a language (as described in
@secref["language-get-info"]), the run-time configuration is a
property of a @emph{module} per se as opposed to a property of
the @emph{source text} representing the module.
For that reason, the run-time configuration for a
module needs to be available even if the module is compiled
to bytecode form and the source is unavailable. Therefore,
run-time configuration cannot be handled by the
@racketidfont{get-info} function we're exporting from the language's
parser module.}
与语言的语法着色属性（如《@secref["language-get-info"]》中所描述的），运行时配置本身是@emph{模块}的属性，而不是表示模块的@emph{源文本}属性。为此，即使模块被编译成字节码形式并且源代码不可用，模块的运行时配置也需要可用。因此，运行时配置不能由我们从语言的解析器模块导出的@racketidfont{get-info}函数处理。

@;{Instead, it will be handled by a new
@racket[configure-runtime] submodule that we'll add inside
the parsed @racket[module] form. When a module is run directly
with @exec{racket}, @exec{racket} looks for a
@racket[configure-runtime] submodule. If it exists, @exec{racket}
runs it. But if the module is imported into another module,
the @racket['configure-runtime] submodule is ignored. (And if the
@racket[configure-runtime] submodule doesn't exist, @exec{racket}
just evaluates the module as usual.) That means that the
@racket[configure-runtime] submodule can be used for any special
setup tasks that need to happen when the module is run directly.}
相反，它将由一个新的@racket[configure-runtime](配置运行时)子模块处理，我们将在解析后的@racket[module]表中添加该子模块。当一个模块直接用@exec{racket}运行，@exec{racket}会查找一个@racket[configure-runtime]子模块。如果它存在，@exec{racket}就运行它。但是，如果将模块导入到另一个模块中，则会忽略@racket['configure-runtime]子模块。（如果@racket['configure-runtime]子模块不存在，@exec{racket}会照常对模块求值。）这意味着@racket['configure-runtime]子模块可用于直接运行模块时需要执行的任何特殊设置任务。

@;{Going back to the @racket[literal] language (see
@secref["language-get-info"]), we can adjust the language so that
directly running a @racket[literal] module causes it to print out its
string, while using a @racket[literal] module in a larger program
simply provides @racketidfont{data} without printing. To make this
work, we will need an extra module. (For clarity here, we will implement 
this module as a separate file. But it could equally well be 
a submodule of an existing file.)}
回到@racket[literal]语言（请参见《@secref["language-get-info"]》），我们可以调整语言，以便直接运行@racket[literal]模块可以使其打印出字符串，而在更大的程序中使用@racket[literal]模块只需提供@racketidfont{data}而不打印。为了完成这项工作，我们需要一个额外的模块。（为了清楚起见，我们将把这个模块实现为一个单独的文件现有文件的子模块。）

@racketblock[
.... @;{@#,elem{(the main installation or the user's space)}}@#,elem{（主要安装或用户空间）}
!- @#,filepath{literal}
   !- @#,filepath{main.rkt}            @;{@#,elem{(with reader submodule)}}@#,elem{（带读卡器子模块）}
   !- @#,filepath{show.rkt}            @;{@#,elem{(new)}}@#,elem{（新增）}
]

@itemlist[

 @;{@item{The @filepath{literal/show.rkt} module will provide a
       @racketidfont{show} function to be applied to the string
       content of a @racket[literal] module, and also provide a
       @racketidfont{show-enabled} parameter that controls whether
       @racketidfont{show} actually prints the result.}}
  @item{@filepath{literal/show.rkt}模块将提供一个@racketidfont{show}函数以被应用到一个@racket[literal]（文本）模块的字符串内容，同时也提供一个@racketidfont{show-enabled}参数，它控制是否@racketidfont{show}的实际打印结果。}

 @;{@item{The new @racket[configure-runtime] submodule in
       @filepath{literal/main.rkt} will set the
       @racketidfont{show-enabled} parameter to @racket[#t]. The
       net effect is that @racketidfont{show} will print the strings
       that it's given, but only when a module using the @racket[literal]
       language is run directly (because only then will the
       @racket[configure-runtime] submodule be invoked).}}
@item{@filepath{literal/main.rkt}中新的@racket[configure-runtime]子模块将@racketidfont{show-enabled}参数设置为@racket[#t]。最终的效果是，@racketidfont{show}将打印给定的字符串，但只有当使用@racket[literal]语言的模块直接运行时（因为只有这样才能调用@racket[configure-runtime]子模块）。}

]


@;{These changes are implemented in the following revised
@filepath{literal/main.rkt}:}
这些更改在以下修订的@filepath{literal/main.rkt}中实现：

@racketmodfile["literal-main-language-info.rkt" "literal/main.rkt"]

@;{Then the @filepath{literal/show.rkt} module must provide
the @racketidfont{show-enabled} parameter and @racketidfont{show}
function:}
然后@filepath{literal/show.rkt}模块必须提供@racketidfont{show-enabled}参数和@racketidfont{show}函数：

@racketmod[
#:file "literal/show.rkt"
racket

(provide show show-enabled)

(define show-enabled (make-parameter #f))

(define (show v)
  (when (show-enabled)
    (display v)))
]

@;{With all of the pieces for @racket[literal] in place, try running the
following variant of @filepath{tuvalu.rkt} directly and through a
@racket[require] from another module:}
有了@racket[literal]的所有片段后，尝试直接运行@filepath{tuvalu.rkt}的以下变体，并通过另一个模块中的@racket[require]：

@racketmod[
#:file "tuvalu.rkt"
@#,racket[literal]
Technology!
System!
Perfect!
]

@;{When run directly, we'll see the result printed like so, because
our @racket[configure-runtime] submodule will have set the
@racketidfont{show-enabled} parameter to @racket[#t]:}
当直接运行时，我们会看到这样打印的结果，因为我们的@racket[configure-runtime]子模块将@racketidfont{show-enabled}参数设置为@racket[#t]：

@racketblock[
@#,racketoutput{Technology!
@(linebreak)System!
@(linebreak)Perfect!}
]

@;{But when imported into another module, printing will be suppressed,
because the @racket[configure-runtime] submodule will not be invoked,
and therefore the @racketidfont{show-enabled} parameter will remain
at its default value of @racket[#f].}
但是，当导入到另一个模块中时，打印将被抑制，因为不会调用@racket[configure-runtime]子模块，因此@racketidfont{show-enabled}参数将保持其默认值@racket[#f]。